package com.loren.tetris.data;

import com.loren.tetris.data.constant.DataConstant;
import com.loren.tetris.data.entity.Block;
import com.loren.tetris.data.entity.BlockShape;
import com.loren.tetris.data.entity.DiskInfo;
import com.loren.tetris.utils.AssistiveUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class GameData implements Serializable {

    private static final long serialVersionUID = -874759952065473558L;

    /**
     * 游戏地图 - 横向坐标 = 10, 纵向坐标 = 20
     */
    private final Block[][] gameMap = new Block[10][20];

    /**
     * 当前方块
     */
    private BlockShape current;

    /**
     * 下一个方块
     */
    private BlockShape next;

    /**
     * 游戏是否结束
     */
    private boolean gameOver = true;

    /**
     * 是否开启阴影效果
     */
    private boolean enableShadow = false;

    /**
     * 游戏是否暂停
     */
    private boolean gamePause = false;

    /**
     * 本地记录列表
     */
    private List<DiskInfo> diskInfoList;

    /**
     * 游戏得分
     */
    private int gameScore = 0;

    /**
     * 游戏消行数量
     */
    private int gameRemoveCount = 0;

    /**
     * 游戏等级
     */
    private int gameGrade = 0;

    /**
     * 游戏时间 - 时
     */
    private int gameTimeHour = 0;

    /**
     * 游戏时间 - 分
     */
    private int gameTimeMinute = 0;

    /**
     * 游戏时间 - 秒
     */
    private int gameTimeSecond = 0;

    public GameData() {
        this.current = BlockShape.blockShapeRandom();
        this.next = BlockShape.blockShapeRandom();
        this.diskInfoList = this.getDiskRecordList();
    }

    public Block[][] getGameMap() {
        return gameMap;
    }

    public BlockShape getCurrent() {
        return current;
    }

    public void setCurrent(BlockShape current) {
        this.current = current;
    }

    public BlockShape getNext() {
        return next;
    }

    public void setNext(BlockShape next) {
        this.next = next;
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public void setGameOver(boolean gameOver) {
        this.gameOver = gameOver;
    }

    public boolean isEnableShadow() {
        return enableShadow;
    }

    public void setEnableShadow(boolean enableShadow) {
        this.enableShadow = enableShadow;
    }

    public boolean isGamePause() {
        return gamePause;
    }

    public void setGamePause(boolean gamePause) {
        this.gamePause = gamePause;
    }

    public List<DiskInfo> getDiskInfoList() {
        return diskInfoList;
    }

    public int getGameScore() {
        return gameScore;
    }

    public void setGameScore(int gameScore) {
        this.gameScore = gameScore;
    }

    public int getGameRemoveCount() {
        return gameRemoveCount;
    }

    public void setGameRemoveCount(int gameRemoveCount) {
        this.gameRemoveCount = gameRemoveCount;
    }

    public int getGameGrade() {
        return gameGrade;
    }

    public void setGameGrade(int gameGrade) {
        this.gameGrade = gameGrade;
    }

    public int getGameTimeHour() {
        return gameTimeHour;
    }

    public void setGameTimeHour(int gameTimeHour) {
        this.gameTimeHour = gameTimeHour;
    }

    public int getGameTimeMinute() {
        return gameTimeMinute;
    }

    public void setGameTimeMinute(int gameTimeMinute) {
        this.gameTimeMinute = gameTimeMinute;
    }

    public int getGameTimeSecond() {
        return gameTimeSecond;
    }

    public void setGameTimeSecond(int gameTimeSecond) {
        this.gameTimeSecond = gameTimeSecond;
    }

    /**
     * 本地记录列表 key = name, value = score
     */
    @SuppressWarnings("unchecked")
    private List<DiskInfo> getDiskRecordList() {
        List<DiskInfo> diskRecordList;
        String recordFilePath = AssistiveUtils.getAbsoluteFilePath(DataConstant.PATH_GAME_DISK_RECORD);
        this.createDiskRecordFile(recordFilePath);
        try (
                ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(recordFilePath))
        ) {
            diskRecordList = ((List<DiskInfo>) inputStream.readObject());
        } catch (Exception e) {
            diskRecordList = new ArrayList<>();
        }
        if (diskRecordList.size() < 5) {
            for (int i = diskRecordList.size(); i < 5; i++) {
                diskRecordList.add(new DiskInfo("none", 0));
            }
        } else if (diskRecordList.size() > 5) {
            diskRecordList = new ArrayList<>(diskRecordList.subList(0, 5));
        }
        return diskRecordList;
    }

    /**
     * 保存本地记录
     */
    public void saveDiskRecordList(String name) {
        this.diskInfoList = new ArrayList<>();
        List<DiskInfo> diskList = this.getDiskRecordList();
        boolean addCurrentPlayer = true;
        for (DiskInfo diskInfo : diskList) {
            if (addCurrentPlayer && this.gameScore > diskInfo.getScore()) {
                this.diskInfoList.add(new DiskInfo(name, this.gameScore));
                addCurrentPlayer = false;
            }
            this.diskInfoList.add(diskInfo);
        }
        this.diskInfoList = new ArrayList<>(this.diskInfoList.subList(0, 5));
        String recordFilePath = AssistiveUtils.getAbsoluteFilePath(DataConstant.PATH_GAME_DISK_RECORD);
        try (
                ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(recordFilePath))
        ) {
            outputStream.writeObject(this.diskInfoList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 如果本地的记录文件不存在，则创建默认的本地记录文件
     */
    private void createDiskRecordFile(String filePath) {
        File file = new File(filePath);
        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            if (parentFile.mkdir()) {
                try (
                        FileOutputStream fileOutputStream = new FileOutputStream(file)
                ) {
                    fileOutputStream.flush();
                } catch (Exception e) {
                    throw new RuntimeException("create file failure");
                }
            }
        }
    }
}
